package cn.cxyxj.code_auth_jwt_persistence_prod.config;

import cn.cxyxj.code_auth_jwt_persistence_prod.auth.UsernamePasswordJsonAuthenticationFilter;
import cn.cxyxj.code_auth_jwt_persistence_prod.auth.filter.JwtTokenFilter;
import cn.cxyxj.code_auth_jwt_persistence_prod.auth.handler.*;
import cn.cxyxj.code_auth_jwt_persistence_prod.service.impl.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    UserDetailsServiceImpl userService;
    @Autowired
    private CustomizeLogoutSuccessHandler customizeLogoutSuccessHandler;
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 设置 UserDetailsService
        auth.userDetailsService(userService);
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 放行的接口
        String[] urls = new String[]{"/auth-login"};
        // 这行需要加上，否则请求参数需要带上 _csrf
        http.cors().and().csrf().disable();
        // 配置后 不能再使用 formLogin 页面登录
        http.exceptionHandling().authenticationEntryPoint(new CustomizeAuthenticationEntryPoint()).accessDeniedHandler(new CustomizeAccessDeniedHandler());
        // 不需要登录就能访问
        http.authorizeRequests().antMatchers(urls).permitAll().antMatchers(HttpMethod.OPTIONS).permitAll().anyRequest().authenticated();

        //http.formLogin().successHandler(new CustomizeAuthenticationSuccessHandler()).failureHandler(new CustomizeAuthenticationFailureHandler()).permitAll();
        // 禁用 session，不再生成 JSESSIONID
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).disable();
        // 将 UsernamePasswordJsonAuthenticationFilter 放置在 UsernamePasswordAuthenticationFilter 的位置，解析 JSON 报文格式登录参数
        http.addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class);
        // 在 UsernamePasswordJsonAuthenticationFilter 之前添加一个 Filter
        http.addFilterBefore(new JwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);

        http.logout().logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler())
                .addLogoutHandler(customizeLogoutSuccessHandler)
                .clearAuthentication(true);
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }


    @Bean
    public UsernamePasswordJsonAuthenticationFilter loginFilter() throws Exception {
        UsernamePasswordJsonAuthenticationFilter loginFilter = new UsernamePasswordJsonAuthenticationFilter();
        loginFilter.setAuthenticationManager(authenticationManagerBean());
        // 配置登录接口
        loginFilter.setFilterProcessesUrl("/auth-login");
        // 登录参数名
        loginFilter.setUsernameParameter("account");
        loginFilter.setPasswordParameter("password");
        // 登录成功回调
        loginFilter.setAuthenticationSuccessHandler(new CustomizeAuthenticationSuccessHandler());
        // 登录异常回调
        loginFilter.setAuthenticationFailureHandler(new CustomizeAuthenticationFailureHandler());
        return loginFilter;
    }
}
